class MVVM {
    constructor(options) {
        this.$el = options.el;
        this.$data = options.data;
        if(this.$el){
            //数据劫持
            new Observer(this.$data)
            //编译 模板+数据
            new Compile(this.$el ,this)
        }
    }
}
//类似于明星
class Dep{
    constructor(){
        this.Watchers = [];
    }
    add(Watcher){
        this.Watchers.push(Watcher)
    }
    notify(){
        this.Watchers.forEach(Watcher=>{
            Watcher.update();
        })
    }
}
//观察者
class Watcher{
    constructor(vm,expr,callback){
        this.vm = vm;
        this.expr = expr;
        this.callback = callback;
        //获取上一的值
        this.oldValue = this.get();
    }
    get(){
        Dep.target = this;
        let value = compileUtil.getVal(this.expr,this.vm);
        return value
    }
    update(){
        let newVal = compileUtil.getVal(this.expr,this.vm)
        if(newVal != this.oldValue){
            this.callback(newVal)
        }
    }
}
//vm.$watch(vm,"user.name",(newVal)=>{})
//数据劫持  =====>>>>  观察模式 实例 必经之路
class Observer{
    constructor(data){
        this.observer(data);
    }
    observer(data){
        //判断data是否存在  并且是否是对象
        if(data && typeof data === 'object'){
            for(let key in data){
                //劫持            //数据 键  键值
                this.observerData(data,key,data[key]);
            }
        }
    }
    observerData(data,key,value){
        this.observer(value);
        let dep = new Dep();
        Object.defineProperty(data,key,{
            set(newVal){
                console.log('设置值')
                value = newVal;
                dep.notify()//相当于通知
            },
            get(){
                //添加观察者
                Dep.target && dep.add(Dep.target);
                console.log('获取值')
                return value
            }
        }) 
    }
}

//编译

class Compile{
    constructor(el,vm){
        this.vm = vm;
        this.el = this.isElementNode(el)?el : document.querySelector(el)
        //把html节点放到内存里面去
        let fragment = this.nodeToElement(this.el);
        console.log(fragment)

        //编译之后
        this.el.appendChild(fragment)
    }
    //编译元素
    compileElement(node){//标签 
        console.log(node,'------------');
        //获取元素的所有属性
        let attribute = node.attributes;
        //判断属性是否是v-
        [...attribute].forEach(item=>{
            let {name ,value ,expr} = item;
            //name 属性名  v-model  expr 属性值
            if(this.isDirective(name)){
                //该属性是指令
                let [directive]= name.split('-')
                compileUtil[directive](node,expr)
            }
        })
    }
    isDirective(attr){
        return attr.startsWith('v-')
    }
    //编译文本
    compileText(node){
        console.log(node,"+++++++++++++")
        //node.textContent //当前文本节点的内容
        let content = node.textContent;
        //判断是否含有{{}}
        if(/\{\{(.+?)\}\}/.test(content)){

        }
    }
    //编译类型
    compile(node){
        let childNodes = node.childNodes;
        console.log(childNodes);
        [...childNodes].forEach(item=>{
            // 1.判断当前是 元素还是文本
            if(this.isElementNode(item)){//元素
                this.compileElement(item)
                this.compile(item)
            }else{//文本
                this.compileText(item)
            }
        })
    }
    //把html节点当道内存中
    nodeToElement(node){
        //创建文档片段
        //把子元素插入到文档片段
        let fragment = document.createDocumentFragment();
        let firstChild;
        //循环吧node 的子节点放到文档片段内
        while(firstChild = node.firstChild){
            fragment.appendChild(firstChild)
        }
        return fragment;
    }
    //判断是否是元素
    isElementNode(node){
        //元素节点 1  属性节点 2 文本节点  
        return node.nodeType === 1
    }
}
let compileUtil = {
    //获取值从vm.$data//查找user.name 表达式的值 给node节点value的值
    getVal(expr,vm){
        //[user.name]
        /**
         * {
         *      user:{
         *              name:"kk"
         *       }
         *       info:"123"
         * }
         */
        return  expr.split('.').reduce((pre,current)=>{
            return pre[current]
          },vm.$data)
    },
    model(node,expr,vm){
        //从vm.$data//查找user.name 表达式的值 给node节点value的值
        let value = this.getVal(expr,cm)
        // node.value = value
        let fn = this.update.compileModel;
        new Watcher(vm,expr,(newVal)=>{
            fn(node,newVal)
        })
        fn(node,value)
    },
    //{{expr}}  {{user.name}}  user.name ===> kk
    content(node,content,vm){
        let value = content.replace(/\{\(.+?)\}\}/g,(...argv)=>{
            console.log(arge[1])
            new Watcher(vm,arge[1],(newVal)=>{
                fn(node,newVal)
            })
            return this.getVal(argv[1],vm)
        })
        console.log(value)
    },
    text(){
        
    },
    html(){
         
    },
    updater:{
        compileModel(node,value){
            node.value = value
        },
        compileContent(node,value){
            node.testContent = value
        }
    }
}